////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//                                                                                                                            //
//                                                         WNProject                                                          //
//                                                                                                                            //
//            This file is distributed under the BSD 2-Clause open source license. See License.txt for details.               //
//                                                                                                                            //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#ifndef __WN_THREAD_H__
#define __WN_THREAD_H__

#include "WNCore/inc/WNBase.h"

#ifdef _WN_WINDOWS
    #include <windows.h>

    #define WN_THREAD_INFINITE_TIMEOUT INFINITE

    typedef HANDLE WN_THREAD_T;
    typedef DWORD WN_THREAD_ID_T;

    WN_STDCALL_FUNCTION_TYPEDEF(WN_THREAD_FUNCTION_T, WN_UINT32, WN_VOID*);

    #define WN_THREAD_FUNCTION(_function, _parameter) WN_UINT32 __WN_STDCALL_BEGIN _function(WN_VOID* _parameter) __WN_STDCALL_END

    #define WN_THREAD_PRIORITY_LOWEST THREAD_PRIORITY_LOWEST
    #define WN_THREAD_PRIORITY_BELOW_NORMAL THREAD_PRIORITY_BELOW_NORMAL
    #define WN_THREAD_PRIORITY_NORMAL THREAD_PRIORITY_NORMAL
    #define WN_THREAD_PRIORITY_HIGHEST THREAD_PRIORITY_HIGHEST
    #define WN_THREAD_PRIORITY_ABOVE_NORMAL THREAD_PRIORITY_ABOVE_NORMAL

    #define WN_THREAD_PRIORITY_TIME_CRITICAL THREAD_PRIORITY_TIME_CRITICAL
    #define WN_THREAD_PRIORITY_IDLE THREAD_PRIORITY_IDLE
#elif defined _WN_LINUX
    #include <pthread.h>
    #include <unistd.h>

    typedef pthread_t WN_THREAD_T;
    typedef pid_t WN_THREAD_ID_T;

    WN_CDECL_FUNCTION_TYPEDEF(WN_THREAD_FUNCTION_T, WN_VOID*, WN_VOID*);

    #define WN_THREAD_FUNCTION(_function, _parameter) extern "C" WN_VOID* __WN_CDECL_BEGIN _function(WN_VOID* _parameter) __WN_CDECL_END

    #define WN_THREAD_PRIORITY_LOWEST -2
    #define WN_THREAD_PRIORITY_BELOW_NORMAL -1
    #define WN_THREAD_PRIORITY_NORMAL 0
    #define WN_THREAD_PRIORITY_HIGHEST 1
    #define WN_THREAD_PRIORITY_ABOVE_NORMAL 2

    #define WN_THREAD_PRIORITY_TIME_CRITICAL 15
    #define WN_THREAD_PRIORITY_IDLE -15
#endif

#ifndef WN_THREAD_INFINITE_TIMEOUT
    #define WN_THREAD_INFINITE_TIMEOUT 0xFFFFFFFF
#endif

__WN_INLINE WN_UINT32 WNThreadCreate(WN_THREAD_T* _thread, WN_THREAD_FUNCTION_T _startRoutine, WN_VOID* _parameter, WN_SIZE_T _stackSize);
__WN_INLINE WN_THREAD_T WNThreadSelf();
__WN_INLINE WN_THREAD_ID_T WNThreadID();
__WN_INLINE WN_VOID WNThreadYield();
__WN_INLINE WN_VOID WNThreadSleep(WN_UINT32 _milliseconds);
__WN_INLINE WN_VOID WNThreadExit(WN_UINT32 _return);
__WN_INLINE WN_UINT32 WNThreadSetAffinity(WN_THREAD_T _thread, WN_SIZE_T _affinity);
__WN_INLINE WN_UINT32 WNThreadGetAffinity(WN_THREAD_T _thread, WN_SIZE_T* _affinity);
__WN_INLINE WN_UINT32 WNThreadSetPriority(WN_THREAD_T _thread, WN_UINT32 _priority);
__WN_INLINE WN_UINT32 WNThreadGetPriority(WN_THREAD_T _thread, WN_UINT32* _priority);
__WN_INLINE WN_UINT32 WNThreadGetExitCode(WN_THREAD_T _thread, WN_UINT32* _return);
__WN_INLINE WN_UINT32 WNThreadCleanup(WN_THREAD_T _thread);

__WN_INLINE WN_UINT32 WNWaitForSingleThread(WN_THREAD_T _thread);
__WN_INLINE WN_UINT32 WNWaitForSingleThreadTimed(WN_THREAD_T _thread, WN_UINT32 _milliseconds);
__WN_INLINE WN_UINT32 WNWaitForMultipleThreads(const WN_THREAD_T* _threads, WN_UINT32 _count);
__WN_INLINE WN_UINT32 WNWaitForMultipleThreadsTimed(const WN_THREAD_T* _threads, WN_UINT32 _count, WN_UINT32 _milliseconds);

#include "WNConcurrency/inc/WNThread.inl"

#endif // __WN_THREAD_H__